using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Web;
using Spring.Collections;
using Spring.Util;

namespace Spring.TestSupport;

/// <summary>
/// Test environment implementation.
/// </summary>
/// <author>Erich Eichinger</author>
public class VirtualEnvironmentMock : IVirtualEnvironment, IDisposable
{
    private readonly IVirtualEnvironment _prevEnvironment;

    private string _currentVirtualFilePath;
    private string _pathInfo;
    private HttpValueCollection _query;
    private string _currentExecutionFilePath;
    private readonly string _applicationVirtualPath;
    private ISessionState _session = new SessionMock();
    private IDictionary _requestVariables = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable();
    private NameValueCollection requestParams = new NameValueCollection();
    private IDictionary virtualPath2ArtifactsTable = new CaseInsensitiveHashtable();

    public VirtualEnvironmentMock(string currentVirtualFilePath, string pathInfo, string queryText, string applicationVirtualPath, bool autoInitialize)
    {
        _currentVirtualFilePath = currentVirtualFilePath;
        _currentExecutionFilePath = currentVirtualFilePath;
        _pathInfo = (pathInfo == null || pathInfo.Length == 0) ? "" : "/" + pathInfo.TrimStart('/'); // prevent null string and ensure '/' prefixed
        _query = new HttpValueCollection(queryText);
        _applicationVirtualPath = "/" + ("" + applicationVirtualPath).Trim('/');
        if (!_applicationVirtualPath.EndsWith("/")) _applicationVirtualPath = _applicationVirtualPath + "/";

//            if (!_currentVirtualFilePath.StartsWith(_applicationVirtualPath))
//            {
//                throw new ArgumentException("currentVirtualFilePath must begin with applicationVirtualPath");
//            }

        _prevEnvironment = VirtualEnvironment.SetInstance(this);
        if (autoInitialize)
        {
            VirtualEnvironment.SetInitialized();
        }
    }

    public IDictionary VirtualPath2ArtifactsTable
    {
        get { return virtualPath2ArtifactsTable; }
    }

    public string ApplicationVirtualPath
    {
        get { return _applicationVirtualPath; }
    }

    public string CurrentVirtualPath
    {
        get { return _currentVirtualFilePath + _pathInfo; }
    }

    public string CurrentVirtualPathAndQuery
    {
        get
        {
            string result = _currentVirtualFilePath + _pathInfo;
            if (_query.Count > 0)
            {
                result = result + "?" + _query.ToString();
            }

            return result;
        }
    }

    public string CurrentVirtualFilePath
    {
        get { return _currentVirtualFilePath; }
    }

    public string CurrentExecutionFilePath
    {
        get { return this._currentExecutionFilePath; }
        set { this._currentExecutionFilePath = value; }
    }

    public NameValueCollection QueryString
    {
        get { return _query; }
    }

    public string MapPath(string virtualPath)
    {
        string basePath = Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath);
        string resultPath = WebUtils.CreateAbsolutePath(this.CurrentVirtualFilePath, virtualPath);
        resultPath = basePath.TrimEnd('\\') + "\\" + resultPath.Replace('/', '\\').TrimStart('\\');
        return resultPath;
    }

    public IDisposable RewritePath(string newVirtualPath, bool rebaseClientPath)
    {
        IDisposable ctx = new RewriteContext(CurrentVirtualPathAndQuery, false, this);

        int index = newVirtualPath.IndexOf('?');
        if (index >= 0)
        {
            string newQueryString = (index < (newVirtualPath.Length - 1)) ? newVirtualPath.Substring(index + 1) : string.Empty;
            _query = new HttpValueCollection(newQueryString);
            newVirtualPath = newVirtualPath.Substring(0, index);
        }

        _currentVirtualFilePath = newVirtualPath;

        return ctx;
    }

    public Type GetCompiledType(string virtualPath)
    {
        object o = virtualPath2ArtifactsTable[virtualPath];
        if (o == null)
            throw new FileNotFoundException(virtualPath);
        else if (o is Type)
            return (Type) o;
        else
            return o.GetType();
    }

    public object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType)
    {
        object o = virtualPath2ArtifactsTable[virtualPath];
        if (o == null)
            throw new FileNotFoundException(virtualPath);
        else if (o is Type)
            return Activator.CreateInstance((Type) o);
        else
            return o;
    }

    public ISessionState Session
    {
        get { return _session; }
        set { _session = value; }
    }

    public IDictionary RequestVariables
    {
        get { return _requestVariables; }
        set { _requestVariables = value; }
    }

    public NameValueCollection RequestParams
    {
        get { return requestParams; }
    }

    public void Dispose()
    {
        VirtualEnvironment.SetInstance(_prevEnvironment);
    }

    private class RewriteContext : IDisposable
    {
        private string originalPath;
        private bool rebaseClientPath;
        private VirtualEnvironmentMock runtime;

        public RewriteContext(string originalPath, bool rebaseClientPath, VirtualEnvironmentMock runtime)
        {
            this.originalPath = originalPath;
            this.rebaseClientPath = rebaseClientPath;
            this.runtime = runtime;
        }

        public void Dispose()
        {
            if (originalPath != null)
            {
                this.runtime.RewritePath(originalPath, rebaseClientPath);
            }
        }
    }

    private class HttpValueCollection : NameValueCollection
    {
        public HttpValueCollection(string queryText)
        {
            FillFromString(queryText, false, Encoding.UTF8);
        }

        public override string ToString()
        {
            return ToString(true);
        }

        private void FillFromString(string s, bool urlencoded, Encoding encoding)
        {
            int num = (s != null) ? s.Length : 0;
            for (int i = 0; i < num; i++)
            {
                int startIndex = i;
                int num4 = -1;
                while (i < num)
                {
                    char ch = s[i];
                    if (ch == '=')
                    {
                        if (num4 < 0)
                        {
                            num4 = i;
                        }
                    }
                    else if (ch == '&')
                    {
                        break;
                    }

                    i++;
                }

                string str = null;
                string str2 = null;
                if (num4 >= 0)
                {
                    str = s.Substring(startIndex, num4 - startIndex);
                    str2 = s.Substring(num4 + 1, (i - num4) - 1);
                }
                else
                {
                    str2 = s.Substring(startIndex, i - startIndex);
                }

                if (urlencoded)
                {
                    base.Add(HttpUtility.UrlDecode(str, encoding), HttpUtility.UrlDecode(str2, encoding));
                }
                else
                {
                    base.Add(str, str2);
                }

                if ((i == (num - 1)) && (s[i] == '&'))
                {
                    base.Add(null, string.Empty);
                }
            }
        }

        internal virtual string ToString(bool urlencoded)
        {
            StringBuilder builder = new StringBuilder();
            int count = this.Count;
            for (int i = 0; i < count; i++)
            {
                string str3;
                string key = this.GetKey(i);
                if (urlencoded)
                {
                    key = HttpUtility.UrlEncodeUnicode(key);
                }

                string str2 = ((key != null) && (key.Length > 0)) ? (key + "=") : "";
                ArrayList list = (ArrayList) base.BaseGet(i);
                int num3 = (list != null) ? list.Count : 0;
                if (i > 0)
                {
                    builder.Append('&');
                }

                if (num3 == 1)
                {
                    builder.Append(str2);
                    str3 = (string) list[0];
                    if (urlencoded)
                    {
                        str3 = HttpUtility.UrlEncodeUnicode(str3);
                    }

                    builder.Append(str3);
                }
                else if (num3 == 0)
                {
                    builder.Append(str2);
                }
                else
                {
                    for (int j = 0; j < num3; j++)
                    {
                        if (j > 0)
                        {
                            builder.Append('&');
                        }

                        builder.Append(str2);
                        str3 = (string) list[j];
                        if (urlencoded)
                        {
                            str3 = HttpUtility.UrlEncodeUnicode(str3);
                        }

                        builder.Append(str3);
                    }
                }
            }

            return builder.ToString();
        }
    }
}
